#if !defined(_CGUIFONT_H)
#define _CGUIFONT_H
#include "CGUIutils.h"
#include "Misc.h"
///////////////////////////////////////////////////////////////////////////////
// CPen


template <bool t_bManaged>
class  CGUIPenT
{
public:
	// Data members
	HPEN m_hPen;

	// Constructor/destructor/operators
	CGUIPenT(HPEN hPen = NULL) : m_hPen(hPen)
	{ }

	~CGUIPenT()
	{
		if(t_bManaged && m_hPen != NULL)
			DeleteObject();
	}

	CGUIPenT<t_bManaged>& operator =(HPEN hPen)
	{
		Attach(hPen);
		return *this;
	}

	void Attach(HPEN hPen)
	{
		if(t_bManaged && m_hPen != NULL && m_hPen != hPen)
			::DeleteObject(m_hPen);
		m_hPen = hPen;
	}

	HPEN Detach()
	{
		HPEN hPen = m_hPen;
		m_hPen = NULL;
		return hPen;
	}

	operator HPEN() const { return m_hPen; }

	bool IsNull() const { return (m_hPen == NULL); }

	// Create methods
	HPEN CreatePen(int nPenStyle, int nWidth, COLORREF crColor)
	{
		ASSERT(m_hPen == NULL);
		m_hPen = ::CreatePen(nPenStyle, nWidth, crColor);
		return m_hPen;
	}

#ifndef UNDER_CE
	HPEN CreatePen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = NULL)
	{
		ASSERT(m_hPen == NULL);
		m_hPen = ::ExtCreatePen(nPenStyle, nWidth, pLogBrush, nStyleCount, lpStyle);
		return m_hPen;
	}
#endif // !UNDER_CE

	HPEN CreatePenIndirect(LPLOGPEN lpLogPen)
	{
		ASSERT(m_hPen == NULL);
		m_hPen = ::CreatePenIndirect(lpLogPen);
		return m_hPen;
	}

	BOOL DeleteObject()
	{
		ASSERT(m_hPen != NULL);
		BOOL bRet = ::DeleteObject(m_hPen);
		if(bRet)
			m_hPen = NULL;
		return bRet;
	}

	// Attributes
	int GetLogPen(LOGPEN* pLogPen) const
	{
		ASSERT(m_hPen != NULL);
		return ::GetObject(m_hPen, sizeof(LOGPEN), pLogPen);
	}

	bool GetLogPen(LOGPEN& LogPen) const
	{
		ASSERT(m_hPen != NULL);
		return (::GetObject(m_hPen, sizeof(LOGPEN), &LogPen) == sizeof(LOGPEN));
	}

#ifndef UNDER_CE
	int GetExtLogPen(EXTLOGPEN* pLogPen) const
	{
		ASSERT(m_hPen != NULL);
		return ::GetObject(m_hPen, sizeof(EXTLOGPEN), pLogPen);
	}

	bool GetExtLogPen(EXTLOGPEN& ExtLogPen) const
	{
		ASSERT(m_hPen != NULL);
		return (::GetObject(m_hPen, sizeof(EXTLOGPEN), &ExtLogPen) == sizeof(EXTLOGPEN));
	}
#endif // !UNDER_CE
};

typedef CGUIPenT<false>   CPenHandle;
typedef CGUIPenT<true>    CPen;


///////////////////////////////////////////////////////////////////////////////
// CBrush

template <bool t_bManaged>
class  CGUIBrushT
{
public:
	// Data members
	HBRUSH m_hBrush;

	// Constructor/destructor/operators
	CGUIBrushT(HBRUSH hBrush = NULL) : m_hBrush(hBrush)
	{ }

	~CGUIBrushT()
	{
		if(t_bManaged && m_hBrush != NULL)
			DeleteObject();
	}

	CGUIBrushT<t_bManaged>& operator =(HBRUSH hBrush)
	{
		Attach(hBrush);
		return *this;
	}

	void Attach(HBRUSH hBrush)
	{
		if(t_bManaged && m_hBrush != NULL && m_hBrush != hBrush)
			::DeleteObject(m_hBrush);
		m_hBrush = hBrush;
	}

	HBRUSH Detach()
	{
		HBRUSH hBrush = m_hBrush;
		m_hBrush = NULL;
		return hBrush;
	}

	operator HBRUSH() const { return m_hBrush; }

	bool IsNull() const { return (m_hBrush == NULL); }

	// Create methods
	HBRUSH CreateSolidBrush(COLORREF crColor)
	{
		ASSERT(m_hBrush == NULL);
		m_hBrush = ::CreateSolidBrush(crColor);
		return m_hBrush;
	}

#ifndef UNDER_CE
	HBRUSH CreateHatchBrush(int nIndex, COLORREF crColor)
	{
		ASSERT(m_hBrush == NULL);
		m_hBrush = ::CreateHatchBrush(nIndex, crColor);
		return m_hBrush;
	}
#endif // !UNDER_CE

#if !defined(UNDER_CE) || (_ATL_VER >= 0x0800)
	HBRUSH CreateBrushIndirect(const LOGBRUSH* lpLogBrush)
	{
		ASSERT(m_hBrush == NULL);
#ifndef UNDER_CE
		m_hBrush = ::CreateBrushIndirect(lpLogBrush);
#else // CE specific
		m_hBrush = ATL::CreateBrushIndirect(lpLogBrush);
#endif // UNDER_CE
		return m_hBrush;
	}
#endif // !defined(UNDER_CE) || (_ATL_VER >= 0x0800)

	HBRUSH CreatePatternBrush(HBITMAP hBitmap)
	{
		ASSERT(m_hBrush == NULL);
		m_hBrush = ::CreatePatternBrush(hBitmap);
		return m_hBrush;
	}

	HBRUSH CreateDIBPatternBrush(HGLOBAL hPackedDIB, UINT nUsage)
	{
		ASSERT(hPackedDIB != NULL);
		const void* lpPackedDIB = GlobalLock(hPackedDIB);
		ASSERT(lpPackedDIB != NULL);
		m_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage);
		GlobalUnlock(hPackedDIB);
		return m_hBrush;
	}

	HBRUSH CreateDIBPatternBrush(const void* lpPackedDIB, UINT nUsage)
	{
		ASSERT(m_hBrush == NULL);
		m_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage);
		return m_hBrush;
	}

	HBRUSH CreateSysColorBrush(int nIndex)
	{
		ASSERT(m_hBrush == NULL);
		m_hBrush = ::GetSysColorBrush(nIndex);
		return m_hBrush;
	}

	BOOL DeleteObject()
	{
		ASSERT(m_hBrush != NULL);
		BOOL bRet = ::DeleteObject(m_hBrush);
		if(bRet)
			m_hBrush = NULL;
		return bRet;
	}

	// Attributes
	int GetLogBrush(LOGBRUSH* pLogBrush) const
	{
		ASSERT(m_hBrush != NULL);
		return ::GetObject(m_hBrush, sizeof(LOGBRUSH), pLogBrush);
	}

	bool GetLogBrush(LOGBRUSH& LogBrush) const
	{
		ASSERT(m_hBrush != NULL);
		return (::GetObject(m_hBrush, sizeof(LOGBRUSH), &LogBrush) == sizeof(LOGBRUSH));
	}
};

typedef CGUIBrushT<false>   CBrushHandle;
typedef CGUIBrushT<true>    CBrush;


///////////////////////////////////////////////////////////////////////////////
// CFont

class  CGUILogFont : public LOGFONT
{
public:
	CGUILogFont()
	{
		memset(this, 0, sizeof(LOGFONT));
	}

	CGUILogFont(const LOGFONT& lf)
	{
		Copy(&lf);
	}

	CGUILogFont(HFONT hFont)
	{
		ASSERT(::GetObjectType(hFont) == OBJ_FONT);
		::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this);
	}

	HFONT CreateFontIndirect()
	{
		return ::CreateFontIndirect(this);
	}

	void SetBold()
	{
		lfWeight = FW_BOLD;
	}

	bool IsBold() const
	{
		return (lfWeight >= FW_BOLD);
	}

	void MakeBolder(int iScale = 1)
	{
		lfWeight += FW_BOLD * iScale;
	}

	void MakeLarger(int iScale)
	{
		if(lfHeight > 0)
			lfHeight += iScale;
		else
			lfHeight -= iScale;
	}

	void SetHeight(LONG nPointSize, HDC hDC = NULL)
	{
		// For MM_TEXT mapping mode
		lfHeight = -MacroMulDiv(nPointSize, ::GetDeviceCaps(hDC, LOGPIXELSY), 72);
	}

	LONG GetHeight(HDC hDC = NULL) const
	{
		// For MM_TEXT mapping mode
		return MacroMulDiv(-lfHeight, 72, ::GetDeviceCaps(hDC, LOGPIXELSY));
	}

	void Copy(const LOGFONT* pLogFont)
	{
		ASSERT(pLogFont != NULL);
		*(LOGFONT*)this = *pLogFont;
	}

	CGUILogFont& operator =(const CGUILogFont& src)
	{
		Copy(&src);
		return *this;
	}

	CGUILogFont& operator =(const LOGFONT& src)
	{
		Copy(&src);
		return *this;
	}

	CGUILogFont& operator =(HFONT hFont)
	{
		ASSERT(::GetObjectType(hFont) == OBJ_FONT);
		::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this);
		return *this;
	}

	bool operator ==(const LOGFONT& logfont) const
	{
		return(logfont.lfHeight == lfHeight &&
			logfont.lfWidth == lfWidth &&
			logfont.lfEscapement == lfEscapement &&
			logfont.lfOrientation == lfOrientation &&
			logfont.lfWeight == lfWeight &&
			logfont.lfItalic == lfItalic &&
			logfont.lfUnderline == lfUnderline &&
			logfont.lfStrikeOut == lfStrikeOut &&
			logfont.lfCharSet == lfCharSet &&
			logfont.lfOutPrecision == lfOutPrecision &&
			logfont.lfClipPrecision == lfClipPrecision &&
			logfont.lfQuality == lfQuality &&
			logfont.lfPitchAndFamily == lfPitchAndFamily &&
			lstrcmp(logfont.lfFaceName, lfFaceName) == 0);
	}
};


template <bool t_bManaged>
class  CGUIFontT
{
public:
	// Data members
	HFONT m_hFont;

	// Constructor/destructor/operators
	CGUIFontT(HFONT hFont = NULL) : m_hFont(hFont)
	{ }

	~CGUIFontT()
	{
		if(t_bManaged && m_hFont != NULL)
			DeleteObject();
	}

	CGUIFontT<t_bManaged>& operator =(HFONT hFont)
	{
		Attach(hFont);
		return *this;
	}

	void Attach(HFONT hFont)
	{
		if(t_bManaged && m_hFont != NULL && m_hFont != hFont)
			::DeleteObject(m_hFont);
		m_hFont = hFont;
	}

	HFONT Detach()
	{
		HFONT hFont = m_hFont;
		m_hFont = NULL;
		return hFont;
	}

	operator HFONT() const { return m_hFont; }

	bool IsNull() const { return (m_hFont == NULL); }

	// Create methods
	HFONT CreateFontIndirect(const LOGFONT* lpLogFont)
	{
		ASSERT(m_hFont == NULL);
		m_hFont = ::CreateFontIndirect(lpLogFont);
		return m_hFont;
	}

#if !defined(UNDER_CE) && (_WIN32_WINNT >= 0x0500)
	HFONT CreateFontIndirectEx(CONST ENUMLOGFONTEXDV* penumlfex)
	{
		ASSERT(m_hFont == NULL);
		m_hFont = ::CreateFontIndirectEx(penumlfex);
		return m_hFont;
	}
#endif // !defined(UNDER_CE) && (_WIN32_WINNT >= 0x0500)

#if !defined(UNDER_CE) || (_ATL_VER >= 0x0800)
	HFONT CreateFont(int nHeight, int nWidth, int nEscapement,
		int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline,
		BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision,
		BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily,
		LPCTSTR lpszFacename)
	{
		ASSERT(m_hFont == NULL);
#ifndef UNDER_CE
		m_hFont = ::CreateFont(nHeight, nWidth, nEscapement,
			nOrientation, nWeight, bItalic, bUnderline, cStrikeOut,
			nCharSet, nOutPrecision, nClipPrecision, nQuality,
			nPitchAndFamily, lpszFacename);
#else // CE specific
		m_hFont = ATL::CreateFont(nHeight, nWidth, nEscapement,
			nOrientation, nWeight, bItalic, bUnderline, cStrikeOut,
			nCharSet, nOutPrecision, nClipPrecision, nQuality,
			nPitchAndFamily, lpszFacename);
#endif // UNDER_CE
		return m_hFont;
	}
#endif // !defined(UNDER_CE) || (_ATL_VER >= 0x0800)

	HFONT CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, HDC hDC = NULL, bool bBold = false, bool bItalic = false)
	{
		LOGFONT logFont = { 0 };
		logFont.lfCharSet = DEFAULT_CHARSET;
		logFont.lfHeight = nPointSize;
		SecureHelper::strncpy_x(logFont.lfFaceName, _countof(logFont.lfFaceName), lpszFaceName, _TRUNCATE);

		if(bBold)
			logFont.lfWeight = FW_BOLD;
		if(bItalic)
			logFont.lfItalic = (BYTE)TRUE;

		return CreatePointFontIndirect(&logFont, hDC);
	}

	HFONT CreatePointFontIndirect(const LOGFONT* lpLogFont, HDC hDC = NULL)
	{
		HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);

		// convert nPointSize to logical units based on hDC
		LOGFONT logFont = *lpLogFont;
#ifndef UNDER_CE
		POINT pt = { 0, 0 };
		pt.y = MacroMulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720);   // 72 points/inch, 10 decipoints/point
		::DPtoLP(hDC1, &pt, 1);
		POINT ptOrg = { 0, 0 };
		::DPtoLP(hDC1, &ptOrg, 1);
		logFont.lfHeight = -abs(pt.y - ptOrg.y);
#else // CE specific
		// DP and LP are always the same on CE
		logFont.lfHeight = -abs(MacroMulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720));   // 72 points/inch, 10 decipoints/point
#endif // UNDER_CE

		if(hDC == NULL)
			::ReleaseDC(NULL, hDC1);

		return CreateFontIndirect(&logFont);
	}

	BOOL DeleteObject()
	{
		ASSERT(m_hFont != NULL);
		BOOL bRet = ::DeleteObject(m_hFont);
		if(bRet)
			m_hFont = NULL;
		return bRet;
	}

	// Attributes
	int GetLogFont(LOGFONT* pLogFont) const
	{
		ASSERT(m_hFont != NULL);
		return ::GetObject(m_hFont, sizeof(LOGFONT), pLogFont);
	}

	bool GetLogFont(LOGFONT& LogFont) const
	{
		ASSERT(m_hFont != NULL);
		return (::GetObject(m_hFont, sizeof(LOGFONT), &LogFont) == sizeof(LOGFONT));
	}
};

typedef CGUIFontT<false>   CGUIFontHandle;
typedef CGUIFontT<true>    CGUIFont;


#endif